import { AlertDialog } from "./alertDialog.js";
import { DICT, COMMON_LETTER } from "./dict.js";

export class CheckList extends HTMLElement {
    #data;
    headers = new Set();
    static EXPECT_KEYS = ['element', 'uuid', '_status', 'searchKey'];
    #noResult;

    setProperty(data) {
        const list = this;
        Object.defineProperty(data, "status", {
            set: function (value) {
                this._status = value;
                this.element?.setAttribute('status', value);
                if (value === CheckList.ITEM_STATUS.REMOVED) {
                    this.element?.setAttribute('status', 'removing');
                    setTimeout(() => {
                        this.element?.setAttribute('status', value);
                    }, 300);
                }
                list.showCurrentItem();
            },
            get: function () {
                return this._status;
            },
        });
    }

    static GenSearchKey(id, info) {
        let searchKey = '';
        for (let i = 0; i < info.length; i++) {
            searchKey += DICT[info[i]] ?? '';
        }
        const len = searchKey.length;
        searchKey += ' ';
        for (let i = 0; i < len; i++) {
            const char = searchKey[i];
            searchKey += COMMON_LETTER[char] ?? char;
        };
        searchKey = searchKey.toLocaleLowerCase();
        return `${id} ${info} ${searchKey}`;
    }

    formatObject(json) {
        const jsonData = { ...json };
        jsonData.data.forEach((element, index) => {
            element[jsonData.name] = String(element[jsonData.name]);
            element.uuid = element.uuid ?? CheckList.GenUUID();
            const status = element._status;
            const ITEM_STATUS = CheckList.ITEM_STATUS;
            if (status && status !== ITEM_STATUS.OK &&
                status !== ITEM_STATUS.LATE && status !== ITEM_STATUS.ABSENT) {
                element._status = status;
            } else {
                element._status = ITEM_STATUS.DEFAULT;
            }
        });
        return jsonData;
    }

    formatArray(arr) {
        const jsonData = [...arr]
        const data = jsonData.map((e, i) => {
            return {
                name: e.toString(),
                uuid: CheckList.GenUUID(),
                _status: CheckList.ITEM_STATUS.DEFAULT,
                searchKey: CheckList.GenSearchKey(i + 1, e),
            }
        });
        return {
            name: 'name',
            data: data ?? [],
        };
    }

    constructor() {
        super();
        const jsonText = this.innerText;
        let jsonData;
        if (jsonText !== '') {
            try {
                jsonData = JSON.parse(jsonText);
                this.data = jsonData;
            } catch (error) {
                console.log(error);
            };
        }

        this.innerHTML = '';
        const shadow = this.attachShadow({ mode: 'open' });
        const style = document.createElement('link');
        style.rel = 'stylesheet';
        style.href = 'css/checkList.css';
        shadow.append(style);
        const noResult = document.createElement('div');
        noResult.textContent = '无匹配项目';
        noResult.classList.add('no-result');
        shadow.append(noResult);
        noResult.style.display = 'none';
        this.#noResult = noResult;
        this.setEventListener();
    }

    /**
     * 
     * @param {{name: string, data: [{key: string}]}} list 
     */
    set data(list) {
        if (this.#data && 'data' in this.#data) {
            this.#data.data.forEach(e => {
                e.element?.remove();
            });
        };
        let formatedList;
        if ('name' in list && 'data' in list) {
            formatedList = this.formatObject(list);
        } else {
            formatedList = this.formatArray(list);
        };
        this.#data = formatedList;
        const { data: data } = list;
        data?.forEach((e, i) => {
            const { element: _element, uuid: uuid, _status: status, searchKey: _searchKey, ...inputs } = e;
            for (let k in inputs) {
                this.headers.add(k);
            }
            if (status !== CheckList.ITEM_STATUS.REMOVED) {
                this.appendItem(e, i + 1)
            }
            this.setProperty(e);
        });
        this.showCurrentItem();
    };

    showCurrentItem(item = this.firstItem) {
        const current = document.querySelector('.actions .current');
        if (item !== undefined) {
            const name = this.name;
            current.innerText = item[name];
            current.item = item;
        } else {
            current.innerText = '核验完成，点击查看报告';
            current.item = {};
        }
    }

    _editItem(item) {
        const name = this.#data.name;
        const headers = this.headers;
        const data = item.data;
        const inputContainer = document.createElement("div");
        const inputsArray = {};
        headers.forEach(key => {
            const input = document.createElement('input');
            inputsArray[key] = input;
            input.placeholder = key;
            input.value = data[key] ?? '';
            inputContainer.append(input);
        });
        new AlertDialog()
            .setTitle('修改信息')
            .setView(inputContainer)
            .setPositiveButton('确定', function () {
                const data = item.data;
                if (inputsArray[name].value === '') {
                    new AlertDialog()
                        .setMessage(`"${name}" 不能为空`)
                        .setPositiveButton('确定')
                        .show()
                } else {
                    for (let key in inputsArray) {
                        const input = inputsArray[key];
                        if (key === name) {
                            item.querySelector('.name').textContent = input.value;
                        }
                        data[key] = input.value;
                    };
                    this.close();
                }
                return true;
            })
            .show();
    }

    setEventListener() {
        const list = this;
        /**
         * 
         * @param {MouseEvent} e   
         */
        const eventListener = function (e) {
            const target = e.target;
            const targetClassList = target.classList;
            const item = target.closest('.item');
            if (targetClassList.contains('remove')) {
                if (item.data.status !== CheckList.ITEM_STATUS.REMOVED) {
                    item.data.status = CheckList.ITEM_STATUS.REMOVED;
                } else {
                    item.data.status = CheckList.ITEM_STATUS.DEFAULT;
                };
                list.showCurrentItem();
            } else if (targetClassList.contains('edit')) {
                list._editItem(item);
            } else if (item) {
                let info = '';
                const expectKeys = CheckList.EXPECT_KEYS;
                for (let key in item.data) {
                    if (expectKeys.indexOf(key) === -1) {
                        info += `${key}: ${item.data[key]} \n`;
                    };
                };
                list.showCurrentItem(item.data);
            }
        }
        this.shadowRoot.addEventListener('click', eventListener);
    }

    get data() {
        return this.#data?.data;
    };

    get name() {
        return this.#data?.name;
    }

    appendItem(itemData, num) {
        const shadow = this.shadowRoot;
        const { uuid } = itemData;
        const name = itemData[this.#data.name];
        const item = document.createElement('div');
        item.classList.add('item');
        item.setAttribute('status', itemData._status ?? CheckList.ITEM_STATUS.DEFAULT);
        item.setAttribute('uuid', uuid);
        item.innerHTML = `<span class="id">${num}</span>
        <span class="name">${name}</span>
        <span class="status"></span>
        <span class="actions">
        <span class="edit"></span>
        <span class="remove"></span>
        </span>`;
        let info = '';
        for (let k in itemData) {
            if (CheckList.EXPECT_KEYS.indexOf(k) === -1) {
                info += itemData[k];
            };
        }
        itemData.searchKey = CheckList.GenSearchKey(num, info);
        shadow.append(item);
        itemData.element = item;
        item.data = itemData;
    }

    append(data) {
        data.uuid = CheckList.GenUUID();
        data._status = CheckList.ITEM_STATUS.DEFAULT;
        this.setProperty(data);
        this.data.push(data);
        this.appendItem(data, this.#data.data.length);
        this.showCurrentItem();
    }

    get firstItem() {
        return this.data?.find(a => {
            return a.status === CheckList.ITEM_STATUS.DEFAULT;
        });
    }

    filter(keywords) {
        if (!this.data) {
            return;
        }
        if (keywords !== '') {
            const lowerKeyWords = keywords.toLocaleLowerCase();
            const regKeyWords = new RegExp(lowerKeyWords.replace(/ /g, '(.+?)?'), 'g');
            this.data?.forEach(e => {
                e.element.style.display = 'none';
            });
            const result = this.data?.filter(e => {
                return e.searchKey.match(regKeyWords) !== null;
            });
            this.#noResult.style.display = '';
            result.forEach(e => {
                e.element.style.display = '';
            });
            if (result.length > 0) {
                this.#noResult.style.display = 'none';
            }
            this.showCurrentItem(result[0]);
        } else {
            this.data.forEach(e => {
                this.#noResult.style.display = 'none';
                e.element.style.display = '';
            });
        }
    }

    static #UUID_POOL = '0123456789abcdefghijklmnopqrstuvwxyz';
    static GenUUID() {
        const uuidLength = 6;
        const pool = CheckList.#UUID_POOL
        const poolLength = pool.length;
        let uuid = '';
        for (let i = 0; i < uuidLength; i++) {
            const n = Math.floor(Math.random() * poolLength);
            uuid += pool[n];
        }
        return uuid;
    }
    static ITEM_STATUS = {
        DEFAULT: 'default',
        OK: 'ok',
        LATE: 'late',
        ABSENT: 'absent',
        REMOVED: 'removed',
    }
}

customElements.define('check-list', CheckList);
